/* 
 * File:   FileObjects.cpp
 * Author: lgr013
 * 
 * Created on 8 de septiembre de 2014, 21:37
 */

#include "FileObjects.h"
#include <cstdint>

FileObjects::FileObjects() {
    this->color = "";
    this->type = "";
    this->height = 0;
    this->mass = 0;
    this->rotation = 0;
    this->scale = 0;
    this->sides = 0;
    this->staticObj = true;
    this->width = 0;
    this->xCoordinate = 0;
    this->yCoordinate = 0;
    this->base = 0;
    this->highParall = 0;
    this->angle1 = 0;
    this->angle2 = 0;
    this->figureTexture=0;
}

bool FileObjects::assignObject(JSON::Object things, FileObjects &fo, int screenPixelX, int screenPixelY, int screenLogicX, int screenLogicY) {
    //Se obtienen los datos del objeto del archivo
    //TODO::VER COMO SALVAR EL ERROR DE TIPOS 

    SBSLog* myLogFile;
    myLogFile->getInstance(MY_LOG_MODE);
    if ((things["tipo"]).type() == JSON::STRING) {
        this->type = ((things["tipo"]).as_string());
        myLogFile->writeInLog(0, "[0] Se parseo exitosamente el tipo de la figura.\n");
    }
    string tipo = (things["tipo"]).as_string();
    bool valido = false;
    //Calcula la relacion de aspecto entre px y ul de la pantalla
    //    this -> screenAspectX = (screenPixelX/screenLogicX);
    //    this -> screenAspectY = (screenPixelY/screenLogicY);
    //Calculo las posiciones del objeto en pxs
    if ((things["x"]).type() == JSON::INT) {
        if ((things["x"]).as_int() >= 0) {
            //if(((things["x"]).as_int() * this->screenAspectX <= screenPixelX){
            if ((things["x"]).as_int() <= screenLogicX) {
                this->xCoordinate = ((things["x"]).as_int());
            }//No entra en la pantalla
            else {
//                cout << "ERROR de posicion invalida" << endl;
                myLogFile->writeInLog(2, "[2] El valor pasado como posicion x de la figura es invalido (no entra en la pantalla).\n");
                return valido;
            }
        }//No es mayor o igual a cero
        else {
//            cout << "ERROR de posicion invalida" << endl;
            myLogFile->writeInLog(2, "[2] El valor pasado como posicion x de la figura es invalido(x<=0).\n");
            return valido;
        }
    }//No es un int
    else {
//        cout << "ERROR de posicion invalida" << endl;
        myLogFile->writeInLog(2, "[2] El valor pasado como posicion x de la figura es invalido (error de tipo).\n");
        return valido;
    }

    if ((things["y"]).type() == JSON::INT) {
        if ((things["y"]).as_int() >= 0) {
            //if(((things["y"]).as_int() * this->screenAspectY) <= screenPixelY){
            if ((things["y"]).as_int() <= screenLogicY) {
                this->yCoordinate = (things["y"]).as_int();
            } else {//No entra en la pantalla
//                cout << "ERROR de posicion invalida" << endl;
                myLogFile->writeInLog(2, "[2] El valor pasado como posicion y de la figura es invalido(no entra en la pantalla).\n");
                return valido;
            }
        }//No es un numero mayor o igual a 0
        else {
//            cout << "ERROR de posicion invalida" << endl;
            myLogFile->writeInLog(2, "[2] El valor pasado como posicion y de la figura es invalido(y<=0).\n");
            return valido;
        }
    }//No es un int
    else {
//        cout << "ERROR de posicion invalida" << endl;
        myLogFile->writeInLog(2, "[2] El valor pasado como posicion y de la figura es invalido (error de tipo).\n");
        return valido;
    }

    //Tipo de objeto RECTANGULO
    if (tipo == "RECTANGLE") {

        if ((things["alto"]).type() == JSON::INT) {
            if ((things["alto"]).as_int() > 0) {
                this->height = ((things["alto"]).as_int());
            }//No es mayor o igual a 0
            else {
                myLogFile->writeInLog(2, "[2] El valor de altura del rectangulo es invalido (alto<=0).\n");
            }
        } else {
            myLogFile->writeInLog(2, "[2] El valor de altura del rectangulo es invalido o no se encontro la etiqueta 'alto' en el archivo.\n");
        }

        if ((things["ancho"]).type() == JSON::INT) {
            if ((things["ancho"]).as_int() > 0) {
                this->width = ((things["ancho"]).as_int());
            }//No es mayor o igual a 0
            else {
                myLogFile->writeInLog(2, "[2] El valor de altura del rectangulo es invalido (ancho<=0).\n");
            }
        } else {
            myLogFile->writeInLog(2, "[2] El valor de ancho del rectangulo es invalido o no se encontro la etiqueta 'ancho' en el archivo.\n");
        }

        valido = true;
    }

    //El tipo de objeto es un paralelogramo
    if (tipo == "PARALLELLOGRAM") {
        if ((things["altura"]).type() == JSON::INT) {
            if ((things["altura"]).as_int() > 0) {
                this->highParall = ((things["altura"]).as_int());
            } else {
                myLogFile->writeInLog(2, "[2] El valor de altura del paralelogramo es invalido (altura<=0).\n");
            }
        } else {
            myLogFile->writeInLog(2, "El valor de alto del paralelogramo es invalido o no se encontro la etiqueta 'altura' en el archivo.\n");
        }

        if ((things["base"]).type() == JSON::INT) {
            if ((things["base"]).as_int() > 0) {
                this->base = ((things["base"]).as_int());
            } else {
                myLogFile->writeInLog(2, "[2] El valor de la base del paralelogramo es invalido (base<=0).\n");
            }
        } else {
            myLogFile->writeInLog(2, "[2] El valor de la base paralelogramo es invalido o no se encontro la etiqueta 'base' en el archivo.\n");
        }

        if ((things["angulo"]).type() == JSON::INT) {
            if ((things["angulo"]).as_int() > 0) {
                int myangulo = (things["angulo"]).as_int();
                this->angle1 = myangulo * M_PI / 180;
            } else {
                myLogFile->writeInLog(2, "[2] El valor del angulo del paralelogramo es invalido (angulo<=0).\n");
            }
        } else {
            myLogFile->writeInLog(2, "[2] El valor del angulo del paralelogramo es invalido o no se encontro la etiqueta 'angulo' en el archivo\n");
        }

        valido = true;
    }
    //El tipo de objeto es un trapecio
    if (tipo == "TRAPEZIUM") {
        if ((things["base"]).type() == JSON::INT) {
            if ((things["base"]).as_int() > 0) {
                this->base = ((things["base"]).as_int());
            } else {
                myLogFile->writeInLog(2, "[2] El valor de baseMayor del trapecio es invalido (baseMayor<=0).\n");
            }
        } else {
            myLogFile->writeInLog(2, "[2] El valor de la base del trapecio es invalido o no se encontro la etiqueta 'base'.\n");
        }

//        if ((things["base2"]).type() == JSON::INT) {
//            if ((things["base2"]).as_int() > 0) {
//                this->base2 = ((things["base2"]).as_int());
//            } else {
//                myLogFile->writeInLog(2, "El valor de baseMenor del trapecio es invalido (baseMenor<=0).\n");
//            }
//        } else {
//            myLogFile->writeInLog(2, "El valor de la base del trapecio es invalido o no se encontro la etiqueta 'base2'.\n");
//        }

        if ((things["altura"]).type() == JSON::INT) {
            if ((things["altura"]).as_int() > 0) {
                this->height = ((things["altura"]).as_int());
            } else {
                myLogFile->writeInLog(2, "[2] El valor de la altura del trapecio es invalido (altura<=0).\n");
            }
        } else {
            myLogFile->writeInLog(2, "[2] El valor de la altura del trapecio es invalido o no se encontro la etiqueta 'altura'.\n");

        }

        if ((things["angulo"]).type() == JSON::INT) {
            if ((things["angulo"]).as_int() > 0) {
                int myangulo = (things["angulo"]).as_int();
                this->angle1 = myangulo * M_PI / 180;
            } else {
                myLogFile->writeInLog(2, "[2] El valor del anguloAlpha del trapecio es invalido (angulo<=0).\n");
            }
        } else {
            myLogFile->writeInLog(2, "[2] El valor del angulo del trapecio es invalido o no se encontro la etiqueta 'angulo'.\n");
        }

        if ((things["angulo2"]).type() == JSON::INT) {
            if ((things["angulo2"]).as_int() > 0) {
                int myangulo2 = (things["angulo2"]).as_int();
                this->angle2 = myangulo2 * M_PI / 180;
            } else {
                myLogFile->writeInLog(2, "[2] El valor del anguloBeta del trapecio es invalido (angulo<=0).\n");
            }
        } else {
            myLogFile->writeInLog(2, "[2] El valor del angulo del trapecio es invalido o no se encontro la etiqueta 'angulo2'. \n");
        }
        valido = true;
    }//if de trapecio

    //El tipo de objeto es un circulo
    if (tipo == "CIRCLE") {
        if ((things["escala"]).type() == JSON::INT) {
            this->scale = (float) ((things["escala"]).as_int());
            myLogFile->writeInLog(1,"[1] Se recibio un INTEGER y se esperaba un FLOAT como radio del circulo [escala], de todos modos se seteo el valor exitosamente.\n");
            } else if ((things["escala"]).type() == JSON::FLOAT) {
            if ((things["escala"]).as_float() > 0) {
                this->scale = ((things["escala"]).as_float());
            } else {
                myLogFile->writeInLog(2, "[2] El valor del radio del circulo es invalido (escala<=0).\n");
            }
        } else {
            myLogFile->writeInLog(2, "[2] El valor del radio del circulo es invalido o no se encontro la etiqueta 'escala'.\n");
        }
        valido = true;
    }//if del circulo

    //El tipo de objeto es un poligono
    if (tipo == "POLYGON") {
        if ((things["escala"]).type() == JSON::INT) {
            this->scale = (float) ((things["escala"]).as_int());
            myLogFile->writeInLog(1,"[1] Se recibio un INTEGER y se esperaba un FLOAT como escala del poligono [escala], de todos modos se seteo el valor exitosamente.\n");
            
        } else if ((things["escala"]).type() == JSON::FLOAT) {
            if ((things["escala"]).as_float() > 0) {
                this->scale = ((things["escala"]).as_float());
            } else {
                myLogFile->writeInLog(2, "[2] El valor del radio del circulo del poligono circunscripto es invalido (escala<=0).\n");
            }
        } else {
            myLogFile->writeInLog(2, "[2] El valor del radio del circulo del poligono circunscripto es invalido o no se encontro la etiqueta 'escala'.\n");
        }

        if ((things["lados"]).type() == JSON::INT) {
            if ((things["lados"]).as_int() > 2) {
                this->sides = ((things["lados"]).as_int());
            } else {
                myLogFile->writeInLog(2, "[2] La cantidad de lados del poligono es invalida (lados<=2).\n");
            }
        } else {
            myLogFile->writeInLog(2, "[2] La cantidad de lados del poligono es invalida o no se encontro la etiqueta 'lados'.\n");
        }
        valido = true;
    }

    if (valido) {
        //Datos comunes a todos los tipos, menos la posicion (debido a validacion x tipo)
        if ((things["textura"]).type() == JSON::INT) {
            if ((things["textura"]).as_int() >= 0) {
                this->figureTexture = (things["textura"]).as_int();
            } //No es un numero mayor o igual a 0
            else {
//                cout << "ERROR de id de textura invalido" << endl;
                myLogFile->writeInLog(2, "[2] El valor pasado como textura de la figura es invalido(y<=0).\n");
                return valido;
            }
        }//No es un int
        else {
//            cout << "ERROR de id de textura invalido" << endl;
            myLogFile->writeInLog(2, "[2] El valor pasado como textura de la figura es invalido (error de tipo).\n");
            return valido;
        }

        if ((things["color"]).type() == JSON::STRING) {
            string colorTest;
            colorTest = (things["color"]).as_string();
            myLogFile->writeInLog(0, "[0] Se pudo parsear correctamente el color desde el archivo, se procedera a validarlo.\n");
            if (this->validateColor(colorTest)) {
                this->makeUpperCase(colorTest);
                this->color = colorTest;
            } else {
                this->color = DEFAULT_COLOR;
                myLogFile->writeInLog(1, "[1] El valor del color es invalido. Se seteara el color por default [DEFAULT_COLOR]\n");
            }
        } else {
            this->color = DEFAULT_COLOR;
            myLogFile->writeInLog(1, "[1] El valor del color es invalido. Se seteara el color por default [DEFAULT_COLOR]\n");
        }
        if ((things["masa"]).type() == JSON::INT) {
            if ((things["masa"]).as_int() > 0) {
                this->mass = ((things["masa"]).as_int());
            } else {//menor a 0
                this->mass = DEFAULT_MASS;
                myLogFile->writeInLog(1, "[1] El valor de la masa es invalido.  Se seteara la masa por default [DEFAULT_MASS].\n");
            }
        } else {//no es un int
            this->mass = DEFAULT_MASS;
            myLogFile->writeInLog(1, "[1] El valor de la masa es invalido.  Se seteara la masa por default [DEFAULT_MASS].\n");
        }
        if ((things["rot"]).type() == JSON::INT) {
            if ((things["rot"]).as_int() >= 0) {
                if ((things["rot"]).as_int() < 360) {
                    this->rotation = ((things["rot"]).as_int()) * M_PI / 180;
                } else {//si los grados no estan entre 0 y 360
                    this->rotation = DEFAULT_ROTATION;
                    myLogFile->writeInLog(1, "[1] El valor de rotacion es invalido.  Se seteara la rotacion por default [DEFAULT_ROTATION].\n");
                }//si los grados no estan entre 0 y 360
            } else {
                this->rotation = DEFAULT_ROTATION;
                myLogFile->writeInLog(1, "[1] El valor de rotacion es invalido.  Se seteara la rotacion por default [DEFAULT_ROTATION].\n");
            }
        } else {//si los grados no son un int
            this->rotation = DEFAULT_ROTATION;
            myLogFile->writeInLog(1, "[1] El valor de rotacion es invalido.  Se seteara la rotacion por default [DEFAULT_ROTATION].\n");
        }
        if ((things["estatico"]).type() == JSON::BOOL) {
            this->staticObj = ((things["estatico"]).as_bool());
            myLogFile->writeInLog(0, "[0] Se identifico correctamente si el objeto es dinamico o estatico.\n");
            } else {//no es un valor valido
                this->staticObj = DEFAULT_STATE;
                myLogFile->writeInLog(1, "[1] No se indico correctamente si la figura es estatica o dinamica.  Se seteara su condicion por default [DEFAULT_STATE].\n");
            }
       } else {
         myLogFile->writeInLog(2, "[2] El tipo de objeto es invalido.  Se descarta.\n");
    }
    return valido;
}

int FileObjects::getBase() {
    return (this -> base); //*(this->screenAspectX);
}

float FileObjects::getAngle1() {
    return this -> angle1;
}

float FileObjects::getAngle2() {
    return this ->angle2;
}

//int FileObjects::getBase2() {
//    return (this->base2); //*(this->screenAspectX);
//}

int FileObjects::getHighParall() {
    return (this->highParall); //*(this->screenAspectY);
}

string FileObjects::getType() {
    return this->type;
}

uint8_t FileObjects::getColorR() {
    int aux, red, tope;
    char auxc;
    red = 0;
    tope = 2;
    //#FF66B2
    for (int posicion = 1; posicion <= tope; ++posicion) {
        aux = (int) (this->color[posicion]);
        aux = aux - 48;
        if (aux > 9) {
            aux = aux - 7;
        }
        if (posicion < tope)
            aux = aux * 16;
        red = red + (aux);
    }
    if (red > 255) {
        return (uint8_t) 255;
    } else {
        if (red < 0) {
            return (uint8_t) 0;
        }
    }

    return (uint8_t) red;
}

uint8_t FileObjects::getColorG() {
    int aux, green, tope, posicion;
    char auxc;
    green = 0;
    tope = 4;

    for (posicion = 3; posicion <= tope; posicion++) {

        aux = (int) (this->color[posicion]);

        aux = aux - 48;
        if (aux > 9) {
            aux = aux - 7;
        }
        if (posicion < tope)
            aux = aux * 16;
        green = green + (aux);
    }
    if (green > 255) {
        return (uint8_t) 255;
    } else {
        if (green < 0) {
            return (uint8_t) 0;
        }
    }
    return (uint8_t) green;
}

uint8_t FileObjects::getColorB() {
    int aux, blue, tope, posicion;
    char auxc;
    blue = 0;
    tope = 6;
    posicion = 5;

    for (posicion; posicion <= tope; posicion = posicion + 1) {

        aux = (int) (this->color[posicion]);
        aux = aux - 48;
        if (aux > 9) {
            aux = aux - 7;
        }
        if (posicion < tope)
            aux = aux * 16;
        blue = blue + (aux);
    }
    if (blue > 255) {
        return (uint8_t) 255;
    } else {
        if (blue < 0) {
            return (uint8_t) 0;
        }
    }
    return (uint8_t) blue;
}

uint8_t FileObjects::getColorA() {
    return (uint8_t) 255;
}

int FileObjects::getSides() {
    return this->sides;
}

int FileObjects::getXCoordinate() {
    return (this->xCoordinate); //*(this->screenAspectX);
}

int FileObjects::getYCoordinate() {
    return (this->yCoordinate); //*(this->screenAspectY);
}

int FileObjects::getHeight() {
    return (this->height); //*(this->screenAspectY);
}

int FileObjects::getWidth() {
    return (this->width); //*(this->screenAspectX);
}

float FileObjects::getRotation() {
    return this->rotation;
}

int FileObjects::getMass() {
    return this->mass;
}

float FileObjects::getScale() {
    return (this->scale);
}

float FileObjects::getRadio() {
    return this->scale;
}

int FileObjects::getFigureTextureID (){
    return this->figureTexture;
}
bool FileObjects::isStatic() {
    return this->staticObj;
}

bool FileObjects::validateColor(string hexaColor) {
    bool success = true;
    SBSLog* myLogFile;
    myLogFile->getInstance(MY_LOG_MODE);
    myLogFile->writeInLog(0, "[0] Se procede a validar el color de la figura\n");
    if (hexaColor.size() != 7) {
        success = false;
        myLogFile->writeInLog(2, "[2] El color no tiene 7 caracteres.\n");
        return success;
    } else {
        int letter;
        letter = (int) (hexaColor[0]);
        if (letter != 35) { //35 = #
            myLogFile->writeInLog(2, "[2] El color no tenia su primer caracter'#'.\n");
            success = false;
            return success;
        } else {
            hexaColor = this->makeUpperCase(hexaColor);
            for (int n = 1; n < 7; ++n) {
                letter = (int) (hexaColor[n]);
                if ((48 > letter) || ((57 < letter)&& (letter < 65)) || (letter > 90)) {
                    success = false;
                    myLogFile->writeInLog(1, "[1] Se parseo un string con un caracter invalido.\n");
                    return success;
                }
            }
        }
    }
    return success;
}

string FileObjects::makeUpperCase(string stringlowcase) {
    string myString;
    string aux;
    int letter;
    myString.append("#");
    for (int i = 1; i < stringlowcase.size(); i++) {
        letter = (int) (stringlowcase[i]);
        
        switch (letter) {
            case 97: myString.append("A");
                break;
            case 98: myString.append("B");
                break;
            case 99: myString.append("C");
                break;
            case 100: myString.append("D");
                break;
            case 101: myString.append("E");
                break;
            case 102: myString.append("F");
                break;
            default: aux = stringlowcase[i];
                myString.append(aux);
        }//fin del switch
    }
    
    return myString;
}

void FileObjects::setType(string tipo) {
    this->type = tipo;
}

void FileObjects::setXCoordinate(int poscx) {
    this->xCoordinate = poscx;
    
}

void FileObjects::setYCoordinate(int poscy) {
    this->yCoordinate = poscy;
    
}

void FileObjects::setWidth(int ancho) {
    this->width = ancho;
    
}

void FileObjects::setHeight(int alto) {
    this->height = alto;
    
}

void FileObjects::setColor(string colorFull) {
    this->color = colorFull;
}

void FileObjects::setRotation(int rotRadianes) {
    this->rotation = rotRadianes;
}

void FileObjects::setMass(int masa) {
    this->mass = masa;
}

void FileObjects::setStatic(bool estatico) {
    this->staticObj = estatico;
}

void FileObjects::setBase(int baseP) {
    this->base = baseP;
    
}

void FileObjects::setHighParall(int altura) {
    this->highParall = altura;
    
}

void FileObjects::setAngle1(float alpha) {
    this->angle1 = alpha;
    
}

FileObjects::~FileObjects() {
    
}
